package de.sendorian.app.forumArchive.domain;


import static org.apache.commons.lang.StringUtils.*;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Transient;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import de.sendorian.app.forumArchive.Config;
import de.sendorian.util.io.FileReader;
import de.sendorian.util.io.FileWriter;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class File {

	private static Logger logger = Logger.getLogger(File.class.getName());

	private static final String AUTHOR_NAMES = "((?:[_-]([a-zA-Z0-9]{2,5}))+)";

	private static final String AUTHOR_NAMES_WRONG_PATTERN = "((?:-([a-zA-Z0-9]{2,5}))+)";

	private static final String NUMBER = "-(\\w)";

	private static final String FILE_EXT = "\\W\\w{3}\\z";

	// e.g. "crate_snd-a.jpg" or "crate_snd.jpg"
	private static final Pattern advancedPattern = Pattern.compile(AUTHOR_NAMES + "(" + NUMBER
	    + ")?" + FILE_EXT);

	// matches e.g. "-a.jpg"
	private static final Pattern numberPattern = Pattern.compile(NUMBER + FILE_EXT);

	// e.g. "crate-snd-a.jpg" or "crate-snd.jpg"
	private static final Pattern wrongPattern = Pattern.compile(AUTHOR_NAMES_WRONG_PATTERN + "("
	    + NUMBER + ")?" + FILE_EXT);

	@Id
	@GeneratedValue
	protected int id;

	protected String name;

	protected String url;

	protected String localPath;


	@Transient
	private byte[] data;


	public File() {
	}


	public File(String url) {
		this.url = url;
	}


	public int getId() {
		return id;
	}


	public String getName() {
		 if (name == null && url != null) {
			int seperatorIndex = url.lastIndexOf('/');
			if (seperatorIndex == -1) {
				seperatorIndex = url.lastIndexOf('\\');
			}

			if (seperatorIndex != -1) {
				name = url.substring(seperatorIndex + 1, url.length());
			}
		}
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public String getUrl() {
		return url;
	}


	public void setUrl(String url) {
		 if (!StringUtils.startsWith(url, "http://")) {
			url = Config.get().getBaseUrl() + url;
		}
		this.url = StringEscapeUtils.unescapeHtml(url);
		name = null;
	}


	public String getLocalPath() {
		return localPath;
	}


	public void setLocalPath(String lokalPath) {
		localPath = lokalPath;
	}


	public byte[] getData() {
		 if (data == null) {
			try {
				data = new FileReader().getFile(getUrl());
			} catch (IOException e) {
				logger.error("Cannot load file data from '" + url + "'", e);
			}
		}
		return data;
	}


	public void setData(byte[] data) {
		 this.data = data;
	}


	@Transient
	public boolean isExternal() {
		return !StringUtils.startsWithIgnoreCase(getUrl(), Config.get().getBaseUrl());
	}


	public boolean save() throws IOException {
		if (getLocalPath() == null) {
			throw new IllegalStateException("Local Path has to be defined to save the file!");
		}

		if (data != null) {
			return new FileWriter().write(data, getLocalPath(), getName());
		} else {
			return new FileReader().save(getUrl(), getLocalPath(), getName());
		}
	}


	public boolean delete() throws IOException {
		if (getLocalPath() == null) {
			throw new IllegalStateException("Local Path has to be defined to delete the file!");
		}

		java.io.File file = new java.io.File(getLocalPath(), getName());
		if (file.exists()) {
			return file.delete();
		}
		return false;
	}

	@Transient
	public String getAuthorAppendix() {
		if (getName() == null) {
			return null;
		}

		Matcher advancedMatcher = advancedPattern.matcher(getName());
		if (advancedMatcher.find()) {
			if (advancedMatcher.groupCount() > 1) {
				return advancedMatcher.group(2);
			}
		}
		return null;
	}

	@Transient
	public String getIndex() {
		if (getName() == null) {
			return null;
		}

		Matcher advancedMatcher = numberPattern.matcher(getName());
		if (advancedMatcher.find()) {
			if (advancedMatcher.groupCount() == 1) {
				return advancedMatcher.group(1);
			}
		}
		return null;
	}

	public String appendUserShortname(String userShortname) {
		if (userShortname != null && getName() != null) {
			String authorAppendix = getAuthorAppendix();
			if (!containsIgnoreCase(authorAppendix, userShortname)) {
				String index = getIndex();
				if (index == null) {
					setName(getNameWithoutExtension() + "_" + userShortname + "." + getExtension());
				} else {
					String name = getNameWithoutExtension();
					setName(name.substring(0, name.lastIndexOf("-")) + "_" + userShortname + "-"
					    + index + "." + getExtension());
				}
			}
		}
		return getName();
	}

	public String checkAndCorrectAuthorAppendix() {
		String name = getName();
		if (name == null) {
			return null;
		}

		Matcher simpleMatcher = wrongPattern.matcher(name);
		if (simpleMatcher.find()) {
			if (simpleMatcher.groupCount() > 1) {
				String authorName = simpleMatcher.group(2);
				name = name.replace("-" + authorName, "_" + authorName);
				setName(name);
				return name;
			}
		}
		return name;
	}

	@Transient
	public String getNameWithoutExtension() {
		String name = getName();
		if (name != null) {
			int extIndex = name.indexOf('.');
			if (extIndex != -1) {
				name = name.substring(0, extIndex);
			}
		}
		return name;
	}

	@Transient
	public String getExtension() {
		String name = getName();
		if (name != null) {
			int extIndex = name.indexOf('.');
			if (extIndex != -1) {
				name = name.substring(extIndex + 1, name.length());
			}
		}
		return name;
	}

	public String toString() {
		return getName();
	}
}
